package bearworker.zxl.server;

import bearworker.zxl.utils.HttpUtil;
import bearworker.zxl.utils.SpringContext;
import bearworker.zxl.utils.UrlUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.QueryStringDecoder;
import io.netty.handler.codec.http.multipart.Attribute;
import io.netty.handler.codec.http.multipart.HttpPostRequestDecoder;
import io.netty.handler.codec.http.multipart.InterfaceHttpData;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.util.CharsetUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.GenericBeanDefinition;

import javax.annotation.Resource;
import java.nio.charset.Charset;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by 逍遥的熊 on 2017/11/25.
 */
public class ServerHandler extends ChannelInboundHandlerAdapter {

    private Logger logger = Logger.getLogger(ServerHandler.class);

    private WebSocketServerHandshaker handshaker;


    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        logger.debug(msg.getClass());
        try {
            // 传统的HTTP接入
            if (msg instanceof FullHttpRequest) {
                handleHttpRequest(ctx, (FullHttpRequest) msg);
            }
            // WebSocket接入
            else if (msg instanceof WebSocketFrame) {
                handleWebSocketFrame(ctx, (WebSocketFrame) msg);
            }
        }catch (Exception e){
            logger.error("读取消息异常",e);
            ctx.close();
        }
    }

    @Override
    public void channelRegistered(ChannelHandlerContext ctx){
        logger.debug("channelId:"+ctx.channel().id());
    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx){
//        logger.debug("用户："+DataMapUtil.getMapUtil().getUser(ctx.channel().id())+"已断线");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx){
//        logger.debug("用户："+DataMapUtil.getMapUtil().getUser(ctx.channel().id())+"已掉线");
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt){
        if (evt instanceof IdleStateEvent) {
            IdleStateEvent e = (IdleStateEvent) evt;
            if (e.state() == IdleState.READER_IDLE) {
//                logger.debug("用户："+DataMapUtil.getMapUtil().getUser(ctx.channel().id())+"已超时连接");
                ctx.close();
            } else if (e.state() == IdleState.WRITER_IDLE) {
                ctx.writeAndFlush(new TextWebSocketFrame("pong"));
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause){
        logger.error("消息异常",cause);
    }

    //http
    private void handleHttpRequest(ChannelHandlerContext ctx,
                                   FullHttpRequest req) throws Exception {

        logger.debug(req.uri());
        logger.debug(req.method());

        // 如果HTTP解码失败，返回HTTP异常
        if(req.decoderResult().isSuccess()){

        }

        // 普通HTTP请求
        if ((!"websocket".equals(req.headers().get("Upgrade")))) {
            sendHttpResponse(ctx, req);
            return;
        }

        // WEBSOCKET 握手
        WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
                "ws://localhost:9876/", null, false);
        handshaker = wsFactory.newHandshaker(req);
        if (handshaker == null) {
            WebSocketServerHandshakerFactory
                    .sendUnsupportedVersionResponse(ctx.channel());
        } else {
            handshaker.handshake(ctx.channel(), req);
        }

    }

    //http响应
    private void sendHttpResponse(ChannelHandlerContext ctx,
                                         FullHttpRequest req) {

        Map<String, String> parmMap = new HashMap<>();

        UrlUtil urlUtil = new UrlUtil();

        HttpUtil httpUtil = new HttpUtil(ctx);

        try {
            //解析类和方法
            String[] urls = {};

            //解析参数
            if (req.method() == HttpMethod.GET) {
                urls = req.uri().substring(0,req.uri().indexOf("?")).split("/");
                QueryStringDecoder decoder = new QueryStringDecoder(req.uri());
                decoder.parameters().entrySet().forEach(entry -> {
                    // entry.getValue()是一个List, 只取第一个元素
                    parmMap.put(entry.getKey(), entry.getValue().get(0));
                });
            } else if (req.method() == HttpMethod.POST) {
                if(req.uri().indexOf("?") > 0) {
                    urls = req.uri().substring(0, req.uri().indexOf("?")).split("/");
                }else {
                    urls = req.uri().split("/");
                }

                QueryStringDecoder decoderP = new QueryStringDecoder(req.uri());
                decoderP.parameters().entrySet().forEach(entry -> {
                    // entry.getValue()是一个List, 只取第一个元素
                    parmMap.put(entry.getKey(), entry.getValue().get(0));
                });


                if (req instanceof HttpContent) {
                    HttpContent httpContent = (HttpContent) req;
                    ByteBuf content = httpContent.content();
                    final StringBuilder buf = new StringBuilder();
                    buf.append(content.toString(CharsetUtil.UTF_8));
                    logger.debug(buf.toString());
                    if(buf.toString().length() > 0) {
                        parmMap.put("bodyStr", buf.toString());
                    }
                }

                HttpPostRequestDecoder decoder = new HttpPostRequestDecoder(req);
                decoder.offer(req);

                List<InterfaceHttpData> parmList = decoder.getBodyHttpDatas();

                for (InterfaceHttpData parm : parmList) {
                    Attribute data = (Attribute) parm;
                    parmMap.put(data.getName(), data.getValue());
                }

            }else {
                logger.debug("参数解析失败，传入未知参数");
                httpUtil.httpRes(500,"参数解析失败，传入未知参数");
            }
            logger.debug(urls[1]+"!!!!!!!"+urls[2]);
            logger.debug(parmMap);
            if(parmMap.size() > 0){
                urlUtil.execute(urls[1],urls[2],parmMap,httpUtil);
            }else {
                httpUtil.httpRes(500,"请求失败，无参数");
            }
        }catch (Exception e){
            logger.error("解析参数错误",e);
            httpUtil.httpRes(500,"参数解析错误");
        }

    }

    //websocket
    private void handleWebSocketFrame(ChannelHandlerContext ctx,
                                      WebSocketFrame frame) {
        String request = "";
        // 本例程仅支持文本消息，不支持二进制消息
        if (frame instanceof TextWebSocketFrame) {
            request = ((TextWebSocketFrame) frame).text();
        }

        if (logger.isDebugEnabled()) {
            logger.debug(String.format("%s received %s", ctx.channel(), request));
        }
        if(StringUtils.isNotEmpty(request)) {
            if (request.endsWith("HeartBeat")) {
                ctx.channel().writeAndFlush(new TextWebSocketFrame("on"));
            } else {
//                ThreadUtil.setTask(new BaseBussEnter(request, ctx));
            }
            frame.release();
        }else {
            frame.release();
        }
    }
}
